package com.doeis.core.db.transaction;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Savepoint;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.doeis.core.db.DBManager;

public class TransactionInterceptor implements MethodInterceptor {
	private static Logger log = Logger.getLogger(TransactionInterceptor.class);

	public Object invoke(MethodInvocation invocation) throws Throwable {
		Method method = invocation.getMethod();
		com.doeis.core.annotation.Transaction transaction = (com.doeis.core.annotation.Transaction) method
				.getAnnotation(com.doeis.core.annotation.Transaction.class);
		int level = transaction.level();
		int propagation = transaction.propagation();

		String datasourceName = transaction.datasource();
		if (StringUtils.isBlank(datasourceName)) {
			datasourceName = DBManager.getDefaultDataSourceName("r".equals(transaction.rw()));
		}

		Object obj = null;
		String methodName = null;
		Connection conn = null;
		Transaction tran = null;
		try {
			methodName = invocation.getMethod().getName();
			tran = TransactionManager.getInstance().getTransaction(datasourceName, methodName);
			tran.setLevel(level);
			tran.setPropagation(propagation);
			conn = DBManager.getConnection(datasourceName);
			conn.setAutoCommit(false);
			conn.setTransactionIsolation(level);
			tran.setConn(conn);

			TransactionManager transactionManager = TransactionManager.getInstance();

			obj = invocation.proceed();
			transactionManager.commit(datasourceName);
		} catch (Exception e) {
			Savepoint savepoint = null;
			if (conn != null) {
				if ((savepoint = TransactionSynchronizer.getLastSavepoint(datasourceName)) != null) {
					conn.rollback(savepoint);
					log.debug("rollback transaction with savepoint ok:" + methodName);
				} else {
					conn.rollback();
					log.debug("rollback transaction ok:" + methodName);
				}
			}
			throw e;
		} finally {
			TransactionSynchronizer.removeTransaction(datasourceName, tran);
			if (propagation == 2) {
				DBManager.closeConnection(conn);
			}
		}
		return obj;
	}
}